/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package VocSymbTest2;

import java.util.Iterator;

/**
 *
 * @author StiggieBig
 */
public class VocabularySymbol implements Comparable<VocabularySymbol> {
    char symbol;
    int pos;
    
    private VocabularySymbolSet<Terminal> first;
    
    public VocabularySymbol() {
    	first = new VocabularySymbolSet<Terminal>();
    }

    //	constructor
    public VocabularySymbol(char termChar, int newPos) {
        symbol = termChar;
        pos = newPos;
        first = new VocabularySymbolSet<Terminal>();
    }

    //	copy constructor
    public VocabularySymbol(VocabularySymbol rhs) {
        symbol = rhs.symbol;
        pos = rhs.pos;
        first = new VocabularySymbolSet<Terminal>();
        first = rhs.first;
    }

    public char GetSymbolChar() {
        return symbol;
    }

    public void Print() {
        System.out.printf("%c", symbol);
    }
    
    public void PrintDebug(){
    	System.out.printf("The symbol %c is of type %s.", symbol, this.getClass());
    	System.out.println("");
    }
    
    public int GetPos(){
    	return pos;
    }
    
    public boolean IsTerm(){
    	return this instanceof Terminal;
    }
    
    public boolean IsNonTerm(){
    	return this instanceof NonTerminal;
    }
    
    public boolean IsSpecSymb(){
    	return this instanceof SpecialSymbol;
    }
    
    public void SetFirst(VocabularySymbolSet<VocabularySymbol> checked, Grammar grammar) {
        boolean hasEmpty = true;
        Terminal empty = (Terminal)(grammar.allTerminals.GetVocSymbFromChar('e'));
        Terminal tempTerminal = new Terminal();
        //	If X is a Terminal, 
        if(this.IsTerm()){
        	//	then First(X) = {X}
            tempTerminal = new Terminal((Terminal)this);
            this.AddToFirst(tempTerminal);
        }
        //	If X is a NonTerminal,
        else if(this.IsNonTerm()){
        	//System.out.print("    ");
        	//this.PrintDebug();
        	//System.out.println();
        	//	For each GrammarRule,
            for(GrammarRule nextGramRule : grammar.allGrammarRules){
            	//System.out.print("        Grammar rule underconsideration is ");
            	//nextGramRule.Print();
            	//System.out.println();
            	//	if this is the source of the grammar rule
                if(this.compareTo(nextGramRule.GetSource()) == 0){
                	//System.out.printf("            %c is the source of this GrammarRule.\n", this.GetSymbolChar());
                	hasEmpty = true;
                	
                	//	Go through all the symbols in the target of the GrammarRule, 
                	//	so long as all previous symbols First contained 'e',
                	//	and union this.First with each successive symbols First set.
                	
                	//	for each symbol in the target of this GrammarRule with all
                	//	previous symbols .First containing 'e'
                	for (Iterator<VocabularySymbol> it = nextGramRule.GetTarget().iterator(); hasEmpty && it.hasNext();) {
                        VocabularySymbol nextVocSymb = it.next();
                        //	If the nextVocSymb has been checked do no check it again
                        //	(otherwise we may enter an infinite loop via something like "E->(E)"
                        if(!checked.isVocSymbElem(nextVocSymb)){
                        	//	add nextVocSymb to the list of checked symbols
                            checked.add(nextVocSymb);
                            //	set nextVocSymb.First
                            nextVocSymb.SetFirst(checked, grammar);
                            //	for each Terminal in  nextVocSymbs .First
                            for(Terminal nextTerm : nextVocSymb.first){
                            	// 	if the symbol has not been added to this.first and the symbol is not 'e'
                                if(!this.GetFirst().isVocSymbElem(nextTerm) && this.compareTo(empty) != 0){
                                    //	add the symbol to this.first
                                	this.AddToFirst(nextTerm);
                                }
                            }
                        }
                        //	check if nextVocSymb.first contains 'e'
                        hasEmpty = nextVocSymb.isInFirst(empty);
                    }
                	//	if all the symbols in the target grammarstring's First set
                	//	contained 'e' or if the production is "this->e"
                    if(hasEmpty || nextGramRule.GetTarget().GetInitialSymb().compareTo(empty) == 0){
                    	//	add 'e' to this.first
                        this.AddToFirst(empty);
                    }
                } /*else {
                	System.out.printf("            %c is not the source of this GrammarRule.\n", this.GetSymbolChar());
                	
                }*/
            }
        }
    }
    
    public void AddToFirst(Terminal terminal){
    	this.first.add(terminal);
    }
    
    public boolean isInFirst(Terminal terminal){
    	return this.first.isVocSymbElem(terminal);
    }
    
    public VocabularySymbolSet<Terminal> GetFirst() {
        return first;
    }
    
    @Override
    public int compareTo(VocabularySymbol v) {
        int symbol1Pos = this.GetPos();
    	int symbol2Pos = ((VocabularySymbol) v).GetPos();
    	return (symbol1Pos - symbol2Pos);
    }
}